#include "Bounding.h"

BSphere::BSphere(void)
{
}

BSphere::BSphere(float r)
: radius(r)
{
}

BSphere::~BSphere(void)
{
}

void BSphere::SetRadius(float r)
{	radius = r;	}

float BSphere::GetRadius(void)
{	return radius;	};

bool BSphere::bContainsBox(BBox b)
{
	// bMax/bMin : max/min coords for target bounding box
	// tMax/tMin : max/min coords for this bounding sphere
	vec3 bMax = b.wPos + b.max, bMin = b.wPos + b.min;
	vec3 tMax = wPos + radius, tMin = wPos - radius;

	return	bMax.x < tMax.x && bMin.x > tMin.x && 
			bMax.y < tMax.y && bMin.y > tMin.y && 
			bMax.z < tMax.z && bMin.z > tMin.z;
}

bool BSphere::bIntersectsBox(BBox b)
{
	float RadSqr = radius * radius;
	return	wPos.distancesquared(b.wPos + b.min) < RadSqr ||
			wPos.distancesquared(b.wPos + b.max) < RadSqr;
}

bool BSphere::bContainsSphere(BSphere s)
{
	// Distance between the two spheres positions squared
	float DistSqrBtwSpheres = wPos.distancesquared( s.wPos );

	// If target sphere is within this sphere,
	// the distance between the two spheres position
	// must be less than this sphere's radius
	return DistSqrBtwSpheres < (radius * radius);
}

bool BSphere::bIntersectsSphere(BSphere s)
{
	// Distance between the two spheres positions squared
	float DistSqrBtwSpheres = wPos.distancesquared( s.wPos );
	// Sum of the radii(radiuses) of the two spheres squared
	float SumSqrOfRadii = (radius + s.radius) * (radius + s.radius);
	
	return DistSqrBtwSpheres < SumSqrOfRadii;
}

bool BSphere::bContainsPoint(vec3 p)
{
	// Distance between the point and the sphere position
	float DistSqrBtwPos = wPos.distancesquared( p );

	// If point is inside sphere,
	// the distance between the position and the point
	// must be less than the sphere's radius
	return DistSqrBtwPos < (radius * radius);
}

BBox::BBox(void)
{
}

BBox::BBox(vec3 Max, vec3 Min)
: max(Max)
, min(Min)
{
}

BBox::~BBox(void)
{
}

void BBox::SetCorners(vec3 Max, vec3 Min)
{
	max = Max;
	min = Min;
}

vec3 BBox::GetTopLeft(void)
{	return min;	};

vec3 BBox::GetBotRight(void)
{	return max;	};

bool BBox::bContainsBox(BBox b)
{
	// bMax/bMin : max/min coords for target bounding box
	// tMax/tMin : max/min coords for this bounding box
	vec3 bMax = b.wPos + b.max, bMin = b.wPos + b.min;
	vec3 tMax = wPos + max, tMin = wPos + min;

	return  bMax.x < tMax.x && bMax.y < tMax.y && bMax.z < tMax.z &&
			bMin.x > tMin.x && bMin.y > tMin.y && bMin.z > tMin.z;
}

bool BBox::bIntersectsBox(BBox b)
{
	// bMax/bMin : max/min coords for target bounding box
	// tMax/tMin : max/min coords for this bounding box
	vec3 bMax = b.wPos + b.max, bMin = b.wPos + b.min;
	vec3 tMax = wPos + max, tMin = wPos + min;

	return	(bMax.x <= tMax.x && bMax.y <= tMax.y && bMax.z <= tMax.z) ||
			(bMin.x >= tMin.x && bMin.y >= tMin.y && bMin.z >= tMin.z);
}

bool BBox::bContainsSphere(BSphere s)
{
	// sMax/sMin : max/min coords for target bounding sphere
	// tMax/tMin : max/min coords for this bounding box
	vec3 sMax = s.wPos + s.radius, sMin = s.wPos - s.radius;
	vec3 tMax = wPos + max, tMin = wPos + min;

	return	sMin.x > tMin.x && sMax.x < tMax.x && 
			sMin.y > tMin.y && sMax.y < tMax.y && 
			sMin.z > tMin.z && sMax.z < tMax.z;
}

bool BBox::bIntersectsSphere(BSphere s)
{
	// sMax/sMin : max/min coords for target bounding sphere
	// tMax/tMin : max/min coords for this bounding box
	vec3 tMax = wPos + max, tMin = wPos + min;
//	float dist_sqr = s.radius * s.radius;
//	
//	if      (s.wPos.x < tMax.x) dist_sqr -= sqr(s.wPos.x - tMax.x);
//	else if	(s.wPos.x > tMin.x) dist_sqr -= sqr(s.wPos.x - tMin.x);
////	if      (s.wPos.y < tMax.y) dist_sqr -= sqr(s.wPos.y + tMax.y);
////	else if (s.wPos.y > tMin.y) dist_sqr -= sqr(s.wPos.y - tMin.y);
//	if      (s.wPos.z < tMax.z) dist_sqr -= sqr(s.wPos.z - tMax.z);
//	else if	(s.wPos.z > tMin.z) dist_sqr -= sqr(s.wPos.z - tMin.z);
//	return	dist_sqr > 0;

	float sum, d = 0;

	for(int i = 0; i < 3; ++i)
	{
		if(s.wPos[i] < tMin[i])
		{
			sum = s.wPos[i] - tMin[i];
			d += sqr(sum);
		}
		else if(s.wPos[i] > tMax[i])
		{
			sum = s.wPos[i] - tMax[i];
			d += sqr(sum);
		}
	}
	return d <= sqr(s.radius);
}

bool BBox::bContainsPoint(vec3 p)
{
	// tMax/tMin : max/min coords for this bounding box
	vec3 tMax = wPos + max, tMin = wPos + min;

	return  p.x >= tMin.x && p.x <= tMax.x &&
			p.y >= tMin.y && p.y <= tMax.y &&
			p.z >= tMin.z && p.z <= tMax.z;
}

void BBox::ContainBox(BBox *b)
{
	// bMax/bMin : max/min coords for target bounding box
	// tMax/tMin : max/min coords for this bounding box
	vec3 bMax = b->wPos + b->max, bMin = b->wPos + b->min;
	vec3 tMax = wPos + max, tMin = wPos + min;

	if(bMin.x < tMin.x) b->wPos.x = tMin.x - b->min.x;
	if(bMin.y < tMin.y) b->wPos.y = tMin.y - b->min.y;
	if(bMin.z < tMin.z) b->wPos.z = tMin.z - b->min.z;
	if(bMax.x > tMax.x) b->wPos.x = tMax.x - b->max.x;
	if(bMax.y > tMax.y) b->wPos.y = tMax.y - b->max.y;
	if(bMax.z > tMax.z) b->wPos.z = tMax.z - b->max.z;
}

void BBox::ContainSphere(BSphere *s)
{
	// sMax/sMin : max/min coords for target bounding sphere
	// tMax/tMin : max/min coords for this bounding box
	vec3 sMax = s->wPos + s->radius, sMin = s->wPos - s->radius;
	vec3 tMax = wPos + max, tMin = wPos + min;

	if(sMax.x > tMax.x) s->wPos.x = tMax.x - s->radius;
	if(sMax.y > tMax.y) s->wPos.y = tMax.y - s->radius;
	if(sMax.z > tMax.z) s->wPos.z = tMax.z - s->radius;
	if(sMin.x < tMin.x) s->wPos.x = tMin.x + s->radius;
	if(sMin.y < tMin.y) s->wPos.y = tMin.y + s->radius;
	if(sMin.z < tMin.z) s->wPos.z = tMin.z + s->radius;
}

void BBox::ContainPoint(vec3 *p)
{
	// tMax/tMin : max/min coords for this bounding box
	vec3 tMax = wPos + max, tMin = wPos + min;

	if(p->x > tMax.x) p->x = tMax.x;
	if(p->y > tMax.y) p->y = tMax.y;
	if(p->z > tMax.z) p->z = tMax.z;
	if(p->x < tMin.x) p->x = tMin.x;
	if(p->y < tMin.y) p->y = tMin.y;
	if(p->z < tMin.z) p->z = tMin.z;
}